﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ConfigLoader.cs" company="SmartPlan">
//   SmartPlan 2011
// </copyright>
// <summary>
//   The config loader.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace DbDiff.Common.Helper
{
    using System;
    using System.IO;
    using System.Text;
    using System.Windows.Forms;
    using System.Xml;
    using Comparer;
    using Model;

    /// <summary>
    /// The config loader.
    /// </summary>
    public class ConfigLoader
    {
        #region Constants

        /// <summary>
        ///   The configfiledefault.
        /// </summary>
        private const string ConfigFileDefaultName = "dbdiff.config.xml";

        /// <summary>
        /// Default folder for saving file
        /// </summary>
        private const string ConfigFileDefaultFolder = @"SmartPlan\DbDiff";

        /// <summary>
        ///   The debugmodedefault.
        /// </summary>
        private const bool Debugmodedefault = false;

        /// <summary>
        ///   The clientwindowminheight.
        /// </summary>
        private const int Clientwindowminheight = 500;

        /// <summary>
        ///   The clientwindowminwidth.
        /// </summary>
        private const int Clientwindowminwidth = 700;

        /// <summary>
        ///   The defaultloglevel.
        /// </summary>
        private const LogLevel Defaultloglevel = LogLevel.Full;

        /// <summary>
        /// scintilla control
        /// </summary>
        private const string scintillaControl1_IsHScrollBar = "scintillaControl1.IsHScrollBar";

        /// <summary>
        /// scintilla control
        /// </summary>
        private const string scintillaControl1_IsVScrollBar = "scintillaControl1.IsVScrollBar";

        /// <summary>
        ///   The defaultlogfile.
        /// </summary>
        private const string Defaultlogfile = "debug.log";

        #endregion Constants 

        #region Config reader - writer methods

        /// <summary>
        /// The load.
        /// </summary>
        /// <param name="encrypted">
        /// The is encrypted.
        /// </param>
        /// <exception cref="DbDiffException">
        /// </exception>
        /// <returns>
        /// The <see cref="Config"/>.
        /// </returns>
        public static Config Load(bool encrypted)
        {
            string localPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), ConfigFileDefaultFolder);

            if (!Directory.Exists(localPath))
            {
                Directory.CreateDirectory(localPath);
            }

            var config = new Config
                             {
                                 ConfigFile = Path.Combine(localPath, AppConfig.GetValue("configfile", ConfigFileDefaultName)),
                                 DebugMode = AppConfig.GetValue("DebugMode", Debugmodedefault.ToString()) == "true"
                             };

            config.IsConfigFile = File.Exists(config.ConfigFile);
            config.RegisteredServers = new RegisteredServerList();
            config.CompareOptions = new SqlCompareOptions();

            config.LogLevel = (LogLevel)Enum.Parse(typeof(LogLevel), AppConfig.GetValue("LogLevel", Defaultloglevel.ToString()), true);
            config.LogFile = Path.Combine(localPath, AppConfig.GetValue("LogFile", Defaultlogfile));

            try
            {
                if (!config.IsConfigFile)
                {
                    config.SetDefaults();
                    return config;
                }

                var configDoc = new XmlDocument();
                string stringValue;

                if (encrypted)
                {
                    byte[] encryptedConfig = File.ReadAllBytes(config.ConfigFile);
                    byte[] decryptedConfig = config.Decrypt(encryptedConfig);
                    var utf8 = new UTF8Encoding();
                    stringValue = utf8.GetString(decryptedConfig);
                    configDoc.LoadXml(stringValue);
                }
                else
                {
                    configDoc.Load(config.ConfigFile);
                }


                XmlNode configNode = configDoc.SelectSingleNode("/dbdiffclient/client");
                if (configNode == null)
                {
                    config.SetClientOptionDefaults();
                }
                else
                {
                    stringValue = XmlHelper.GetChildKeyValue(configNode, "clientwindowstate", FormWindowState.Normal.ToString());
                    config.ClientWindowState = Enum.IsDefined(typeof(FormWindowState), stringValue) ? (FormWindowState) Enum.Parse(typeof(FormWindowState), stringValue, true) : FormWindowState.Normal;

                    if (config.ClientWindowState == FormWindowState.Minimized)
                    {
                        config.ClientWindowState = FormWindowState.Normal;
                    }

                    // ha nem max, csak akkor kell a méret
                    stringValue = XmlHelper.GetChildKeyValue(configNode, "clientwindowwidth", Clientwindowminwidth.ToString());

                    try
                    {
                        config.ClientWindowWidth = Convert.ToInt32(stringValue);
                    }
                    catch (Exception)
                    {
                        config.ClientWindowWidth = Clientwindowminwidth;
                    }

                    // ha nem max, csak akkor kell a méret
                    stringValue = XmlHelper.GetChildKeyValue(configNode, "clientwindowheight", Clientwindowminheight.ToString());

                    try
                    {
                        config.ClientWindowHeight = Convert.ToInt32(stringValue);
                    }
                    catch (Exception)
                    {
                        config.ClientWindowHeight = Clientwindowminheight;
                    }

                    configNode = configDoc.SelectSingleNode("/dbdiffclient/configOption");
                    // bugbug encrypted key backup
                    config = (Config)SerializationHelper.XmlDeSerialize(configNode.InnerXml, config);
                    // bugbug encrypted key restore

                    if (config.RegisteredServers == null)
                    {
                        config.RegisteredServers = new RegisteredServerList();
                    }
                    else
                    {
                        config.RegisteredServers.Clear();
                    }
                    
                    XmlNodeList configNodes = configDoc.SelectNodes("//dbdiffclient/servers/server");
                    RegisteredServer server;
                    if (configNodes != null)
                    {
                        foreach (XmlNode serverNode in configNodes)
                        {
                            server = new RegisteredServer(serverNode);
                            try
                            {
                                config.RegisteredServers.Add(server);
                            }
                            catch (Exception e)
                            {
                                Logger.Instance.Write(e);
                            }
                        }
                    }

                    // Database connectstrings
                    configNode = configDoc.SelectSingleNode("//dbdiffclient/databases/database1");
                    if (configNode != null)
                    {
                        XmlNode serverNode = configNode.SelectSingleNode("server");
                        if (serverNode != null)
                        {
                            server = new RegisteredServer(serverNode);
                            string databaseName = XmlHelper.GetAttributeValue(configNode, "name", true);
                            config.Database1 = new DatabaseInfo(server, databaseName);
                        }
                    }

                    configNode = configDoc.SelectSingleNode("//dbdiffclient/databases/database2");
                    if (configNode != null)
                    {
                        XmlNode serverNode = configNode.SelectSingleNode("server");
                        if (serverNode != null)
                        {
                            server = new RegisteredServer(serverNode);
                            string databaseName = XmlHelper.GetAttributeValue(configNode, "name", true);
                            config.Database2 = new DatabaseInfo(server, databaseName);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                throw new DbDiffException(string.Format("Config file error! Description: {0}", e.Message), e);
            }

            return config;
        }

        /// <summary>
        /// The save.
        /// </summary>
        /// <param name="database1">
        /// The database 1.
        /// </param>
        /// <param name="database2">
        /// The database 2.
        /// </param>
        /// <param name="windowState">
        /// The window state.
        /// </param>
        /// <param name="width">
        /// The width.
        /// </param>
        /// <param name="height">
        /// The height.
        /// </param>
        /// <param name="encrypted">
        /// The is encrypted.
        /// </param>
        /// <param name="config"> </param>
        public static void Save(DatabaseInfo database1, DatabaseInfo database2, FormWindowState windowState, int width, int height, bool encrypted, Config config)
        {
            config.Database1 = database1;
            config.Database2 = database2;
            config.ClientWindowState = windowState;
            config.ClientWindowWidth = width;
            config.ClientWindowHeight = height;

            Save(encrypted, config);
        }

        /// <summary>
        /// The save.
        /// </summary>
        /// <param name="isEncrypted">
        /// The is encrypted.
        /// </param>
        /// <param name="config">
        /// tho config options
        /// </param>
        /// <exception cref="DbDiffException">
        /// </exception>
        public static void Save(bool isEncrypted, Config config)
        {
            try
            {
                var configBuilder = new StringBuilder(string.Empty);

                configBuilder.Append("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n");
                configBuilder.Append("<dbdiffclient version=\"0.1\">\n");
                configBuilder.Append("<client>\n");

                configBuilder.AppendFormat("		<add key=\"clientwindowstate\" value=\"{0}\" />\n", 
                                           config.ClientWindowState);
                configBuilder.AppendFormat("		<add key=\"clientwindowwidth\" value=\"{0}\" />\n", 
                                           config.ClientWindowWidth);
                configBuilder.AppendFormat("		<add key=\"clientwindowheight\" value=\"{0}\" />\n", 
                                           config.ClientWindowHeight);
                configBuilder.Append("	</client>\n");

                configBuilder.Append("	<configOption>\n");
                configBuilder.Append(SerializationHelper.XmlSerialize(config));
                configBuilder.Append("	</configOption>\n");

                configBuilder.Append("	<servers>\n");
                foreach (RegisteredServer server in config.RegisteredServers)
                {
                    configBuilder.Append("		<server name=\"");
                    configBuilder.Append(server.Name);
                    configBuilder.Append("\" authtype=\"");
                    configBuilder.Append(server.AuthType.ToString());
                    configBuilder.Append("\" user=\"");
                    configBuilder.Append(server.User);
                    configBuilder.Append("\" password=\"");
                    configBuilder.Append(server.Password);
                    configBuilder.Append("\" />\n");
                }

                configBuilder.Append("	</servers>\n");
                configBuilder.Append("	<databases>\n");

                if ((config.Database1 != null) && config.Database1.IsConnected)
                {
                    configBuilder.Append("		<database1 name=\"" + config.Database1.Name + "\" >\n");
                    configBuilder.Append("		<server name=\"");
                    configBuilder.Append(config.Database1.Server.Name);
                    configBuilder.Append("\" authtype=\"");
                    configBuilder.Append(config.Database1.Server.AuthType.ToString());
                    configBuilder.Append("\" user=\"");
                    configBuilder.Append(config.Database1.Server.User);
                    configBuilder.Append("\" password=\"");
                    configBuilder.Append(config.Database1.Server.Password);
                    configBuilder.Append("\" />\n");

                    configBuilder.Append("		</database1>\n");
                }

                if ((config.Database2 != null) && config.Database2.IsConnected)
                {
                    configBuilder.Append("		<database2 name=\"" + config.Database2.Name + "\" >\n");
                    configBuilder.Append("		<server name=\"");
                    configBuilder.Append(config.Database2.Server.Name);
                    configBuilder.Append("\" authtype=\"");
                    configBuilder.Append(config.Database2.Server.AuthType.ToString());
                    configBuilder.Append("\" user=\"");
                    configBuilder.Append(config.Database2.Server.User);
                    configBuilder.Append("\" password=\"");
                    configBuilder.Append(config.Database2.Server.Password);
                    configBuilder.Append("\" />\n");
                    configBuilder.Append("		</database2>\n");
                }

                configBuilder.Append("	</databases>\n");
                configBuilder.Append("</dbdiffclient>\n");

                if (isEncrypted)
                {
                    var utf8Enc = new UTF8Encoding();
                    byte[] con = utf8Enc.GetBytes(configBuilder.ToString());
                    byte[] encryptedConfig = config.Encrypt(con);
                    File.WriteAllBytes(config.ConfigFile, encryptedConfig);
                }
                else
                {
                    Logger.Instance.Write(configBuilder.ToString(), LogEventType.Info);
                    var configDoc = new XmlDocument();
                    configDoc.LoadXml(configBuilder.ToString());
                    configDoc.Save(config.ConfigFile);
                }
            }
            catch (Exception e)
            {
                throw new DbDiffException("Configuration save error! Config file: " + config.ConfigFile, e);
            }
        }



        #endregion Config reader - writer methods
    }
}